package com.googlecode.quillen.service;

import com.googlecode.quillen.domain.Snapshot;
import com.googlecode.quillen.domain.Attributes;
import com.googlecode.quillen.domain.AttributeDatabase;
import com.googlecode.quillen.domain.AttributeStorageException;
import com.googlecode.quillen.repository.AttributeStorage;
import com.googlecode.quillen.repository.AttributeStorageQuery;
import static com.googlecode.quillen.util.Utils.logDebug;
import com.googlecode.quillen.util.ResultConsumer;
import com.googlecode.quillen.util.Pair;

import java.util.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

/**
 * Created by IntelliJ IDEA.
 * User: greg
 * Date: Dec 23, 2008
 * Time: 12:28:28 AM
 */
public class SnapshotServiceImpl implements SnapshotService
{
    private static final Log LOG = LogFactory.getLog(SnapshotServiceImpl.class);

    private final AttributeStorage attributeStorage;

    public SnapshotServiceImpl(AttributeStorage attributeStorage)
    {
        this.attributeStorage = attributeStorage;
    }

    public void createStorage() throws AttributeStorageException
    {
        attributeStorage.createDatabase(AttributeDatabase.snapshots.toString());

        logDebug(LOG, "created snapshot storage");
    }

    public void deleteStorage() throws AttributeStorageException
    {
        attributeStorage.deleteDatabase(AttributeDatabase.snapshots.toString());

        logDebug(LOG, "deleted snapshot storage");
    }

    public Snapshot get(String name) throws AttributeStorageException, ParseException
    {
        Attributes attrs = attributeStorage.get(AttributeDatabase.snapshots.toString(), name);

        if (attrs != null)
        {
            return toSnapshot(name, attrs);
        }

        return null;
    }

    public void put(Snapshot snapshot) throws AttributeStorageException
    {
        Attributes attrs = new Attributes();

        attrs.add("date", DateFormatUtils.format(snapshot.getDate(), "yyyyMMddHHmmss"));
        attrs.add("files", Integer.toString(snapshot.getFiles()));
        attrs.add("size", Long.toString(snapshot.getSize()));

        attrs.addReplace(attrs.getKeys());

        attributeStorage.put(AttributeDatabase.snapshots.toString(), snapshot.getName(), attrs);
    }

    public void delete(String name) throws AttributeStorageException
    {
        attributeStorage.delete(AttributeDatabase.snapshots.toString(), name);
    }

    public void list(ResultConsumer<Snapshot> consumer) throws AttributeStorageException, ParseException
    {
        find(null, null, consumer);
    }

    public void find(String prefix, ResultConsumer<Snapshot> consumer) throws AttributeStorageException, ParseException
    {
        find(prefix, null, consumer);
    }

    // TODO: ability to sort and limit results (like to get the most recent snapshot)
    public void find(final String prefix, final Date maxDate, final ResultConsumer<Snapshot> consumer) throws AttributeStorageException, ParseException
    {
        ResultConsumer<Pair<String, Attributes>> results = new ResultConsumer<Pair<String, Attributes>>()
        {
            public void newResult(Pair<String, Attributes> result) throws Exception
            {
                if (consumer != null)
                {
                    consumer.newResult(toSnapshot(result.first, result.second));
                }
            }
        };

        if (StringUtils.isEmpty(prefix) && maxDate == null)
        {
            attributeStorage.list(AttributeDatabase.snapshots.toString(), results);
        }
        else
        {
            AttributeStorageQuery.Condition condition = new AttributeStorageQuery.NotNullCondition("date");

            if (StringUtils.isNotEmpty(prefix))
            {
                condition = new AttributeStorageQuery.ComplexCondition(condition,
                                                                       AttributeStorageQuery.Conjunction.and,
                                                                       new AttributeStorageQuery.LeafCondition("itemName()",
                                                                                                               AttributeStorageQuery.Operator.like,
                                                                                                               prefix + "%"));
            }

            if (maxDate != null)
            {
                condition = new AttributeStorageQuery.ComplexCondition(condition,
                                                                       AttributeStorageQuery.Conjunction.and,
                                                                       new AttributeStorageQuery.LeafCondition("date",
                                                                                                               AttributeStorageQuery.Operator.lessThanOrEqualTo,
                                                                                                               DateFormatUtils.format(maxDate, "yyyyMMddHHmmss")));
            }

            // TODO: order by
//            query += " order by date desc";

            attributeStorage.find(AttributeDatabase.snapshots.toString(), new AttributeStorageQuery(condition), results);
        }
    }

    private Snapshot toSnapshot(String name, Attributes attrs) throws ParseException
    {
        return new Snapshot(name,
                         new SimpleDateFormat("yyyyMMddHHmmss").parse(attrs.getSingle("date")),
                         Integer.valueOf(attrs.getSingle("files")),
                         Long.valueOf(attrs.getSingle("size")));
    }
}
